/**
 * dwr.js
 */
(function(config) {
	var dwr = {};
	var IE = '\v' == 'v';
	var endpoint = config.endpoint || '/phpdwr2/index.php';

	function getRequest() {
		return IE ? new ActiveXObject("Msxml2.XMLHTTP") : new XMLHttpRequest();
	}

	//the server always responds with a JSON string (unless a CDF request); eval with try catch to ensure consistent error handling
	function _evalWithCatch(s, r) {
		try {
			var o = window.eval("(" + s + ")");
			if (typeof(o.status) == "undefined") o.status = "ok";
		} catch(e) {
			var o = {
				"status": "error",
				"error": {
					"detailed_message": "Client-side error\n\n" + e + "\n\n" + strEscapeJSON(s) + "\n\n" + r.status + " " + r.statusText,
					"code": "-1"
				}
			};
		}
		return o;
	}

	function jsonEncode(obj) {
		return JSON.stringify(obj);
	}

	//GENERIC METHOD THAT HANDLES ALL COMMUNICATIONS (SERVICE CALLS) WITH THE REMOTE SERVER
	//objParam: generic parameter object to unpackage; NOTE: the calling method must create a flattened object for this method to work
	//fnCallback: optional callback method
	//strURI: the URI for the Web Service to call
	//strMethod: either get or post
	//bNoEval: if true, the resonse will not be evaluated; if false or null, the server response will be evaluated (the default)
	//arrParam: if the calling method needs to package the parameter object in a unique way, it can pass the array of encoded parameters
	function callService(objParam, fnCallback, strURI, strMethod, bNoEval) {
		var bPost = strMethod.toUpperCase() == "POST";
		var arrParam = new Array();
		if (bPost) {
			for (var p in objParam)
			arrParam.push(p + "=" + window.encodeURIComponent(objParam[p]));
			var strData = arrParam.join("&");
		} else {
			var strDelim = strURI.indexOf("?") > - 1 ? "&": "?";
			for (var p in objParam)
			arrParam.push(p + "=" + window.encodeURIComponent(objParam[p]));
			strURI += strDelim + arrParam.join("&");
			var strData;
		}
		var objRequest = getRequest();
		objRequest.open(strMethod, strURI, fnCallback != null);
		if (bPost) objRequest.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
		return _sendReceive(objRequest, fnCallback, strData, bNoEval);
	};

	//sends the request either async or sync; for beta1, the server will only issue the following HTTP status codes:
	function _sendReceive(r, fnCallback, strContent, bNoEval) {
		if (fnCallback) {
			r.onreadystatechange = function() {
				if (r.readyState == 4) {
					//if the server (a service-oriented Ajax server) throws an error, the response text will be a JSON object with details regarding the error
					if (r.status == 403 || r.status == 404 || r.status == 500) {
						var objR = _evalWithCatch(r.responseText, r);
						objR.httpstatus = r.status;
						fnCallback(objR);
					} else {
						fnCallback(bNoEval ? r.responseText: _evalWithCatch(r.responseText, r));
					}
				}
			};
			r.send(strContent || "");
		} else {
			r.send(strContent || "");
			if (r.status == 403 || r.status == 404 || r.status == 500) {
				var objR = _evalWithCatch(r.responseText, r);
				objR.httpstatus = r.status;
				return objR;
			} else {
				return bNoEval ? r.responseText: _evalWithCatch(r.responseText, r);
			}
		}
	};

	/**
	 * call
	 * call dwr method
	 */
	dwr.call = function(name, parameters) {
		var cb = function() {};
		callService({
			'task': 'call',
			'func': name,
			'param': jsonEncode(Array.prototype.slice.call(parameters))
		},
		function(o) {
			cb(o);
		},
		endpoint, 'POST');
		return {
			when: function(func) {
				cb = func;
			}
		};
	};

	/**
	 * listen
	 * subscribe reverse ajax;
	 */
	dwr.listen = function(name, fnCallback, options) {

	};
	window[config.ns || 'dwr'] = dwr;
})(window['dwrconfig'] || {});

